package com.mxpio.erp.equipment.job;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.mxpio.erp.common.enums.CommonEnums;
import com.mxpio.erp.common.enums.EquipmentEnums;
import com.mxpio.erp.common.equipment.entity.*;
import com.mxpio.erp.common.equipment.service.*;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

/**
 * @Classname GenTaskJob
 * @Description 生成保养任务JOB
 */
@Slf4j
@Component
public class GenUpkeepTaskJob implements Job {

    @Autowired
    private EquipmentUpkeepPlanService tpmUpkeepPlanService;
    @Autowired
    private EquipmentUpkeepPlanTargetService tpmUpkeepPlanTargetService;
    @Autowired
    private EquipmentUpkeepPlanDetailService tpmUpkeepPlanDetailService;
    @Autowired
    private EquipmentUpkeepPlanDetailParamService tpmUpkeepPlanDetailParamService;
    @Autowired
    private EquipmentUpkeepTaskService tpmUpkeepTaskService;
    @Autowired
    private EquipmentUpkeepTaskDetailService tpmUpkeepTaskDetailService;
    @Autowired
    private EquipmentUpkeepTaskDetailParamService tpmUpkeepTaskDetailParamService;

    /**
     * 根据保养计划生成任务（每天凌晨零点五分）
     */
    //@Scheduled(cron = "0 5 0 * * ?")
    @Override
    @Transactional
    public void execute(JobExecutionContext context) throws JobExecutionException {
        log.info(" --- 生成保养任务调度开始 --- ");

        // 查询出要生成保养任务的计划
        /**
         * 查询条件：
         * 1.需要enable的
         * 2.上次计划开始时间之前的（<=）
         * 3.新增计划默認的是创建时间，所以可以使用第二条判断条件
         */
        Criteria c = Criteria.create().addCriterion("isEnable", Operator.EQ, 1);
        //c.addCriterion("lastPlanStart", Operator.LE, new Date());
        List<EquipmentUpkeepPlan> list = tpmUpkeepPlanService.list(EquipmentUpkeepPlan.class, c);


        /**
         * 计划时间计算：
         * 1.组装计划开始时间
         * 1.1 获取开始时间单位，根据时间单位获取当前时间前缀，例如“时”，则时间前缀为2021-10-08 ，“分”则时间前缀为"2021-10-08 10:"
         * 1.2 根据开始时间和频率和频率单位，计算出结束时间
         * 1.3 判断下次开始时间是否超过今日24点，没超过就继续生成本条计划内的任务，超过就不再生成
         */
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        //String formatToday = DateUtil.formatDate(new Date());//yyyy-MM-dd
        for (EquipmentUpkeepPlan plan : list) {
            String endLoopType = plan.getEndLoopType();

            // 获取保养计划目标
            List<EquipmentUpkeepPlanTarget> targets = tpmUpkeepPlanTargetService.selectByMainId(plan.getId());
            if (CollectionUtils.isEmpty(targets)) {
                log.error("计划" + plan.getCode() + "未维护保养目标");
                continue;//跳过
            }

            // 获取保养明细
            List<EquipmentUpkeepPlanDetail> planDetails = tpmUpkeepPlanDetailService.selectByMainId(plan.getId());
            if (CollectionUtils.isEmpty(planDetails)) {
                log.error("计划" + plan.getCode() + "未维护保养明细");
                continue;//跳过
            }
            //计划开始日期
            Date startTime = plan.getStartTime();//计划开始执行的日期
            if (DateUtil.compare(new Date(),startTime)<0) {//没到计划开始执行日期时，跳过
                continue;//跳过
            }
            String planStartDate = DateUtil.formatDate(startTime);//yyyy-MM-dd
            log.info("计划" + plan.getCode() + "开始执行："+DateUtil.formatDateTime(new Date()));
            if (StringUtils.equals(endLoopType, EquipmentEnums.PlanEndLoopType.FREQUENCY.getCode())
                    ||StringUtils.equals(endLoopType, EquipmentEnums.PlanEndLoopType.TIMING.getCode())) {//按频次 或者按时间
                /*Date startTime = plan.getStartTime();//计划开始执行的日期
                if (!StringUtils.equals(DateUtil.formatDate(startTime), DateUtil.formatDate(new Date()))) {//计划开始日期是否等于当前日期（yyyy-MM-dd）
                    continue;//跳过
                }*/
                Integer endTimes;//plan.getEndTimes();//任务生成次数
                if (StringUtils.equals(endLoopType, EquipmentEnums.PlanEndLoopType.FREQUENCY.getCode())){//按频次，直接取值
                    endTimes = plan.getEndTimes();
                }else{//按时间，换算成频次
                    // 获取今日第一条任务
                    Date planEndDate = DateUtil.parseDateTime(DateUtil.formatDate(plan.getEndDate())+" 23:59:59");//计划结束日期
                    String formatPlanStartTime = planStartDate + " " + plan.getTaskPlanStartTime();//任务开始时间
                    DateTime firstPlanStartTime = DateUtil.parse(formatPlanStartTime);
                    Date prePlanStartTime = firstPlanStartTime;
                    int loopIndex = 0;
                    while (DateUtil.compare(prePlanStartTime, planEndDate) <= 0) {
                        loopIndex++;
                        switch (plan.getRateUnit()) {
                            case "日":
                                prePlanStartTime = DateUtils.addDays(firstPlanStartTime, loopIndex * Integer.valueOf(plan.getRate()));
                                break;
                            case "月":
                                prePlanStartTime = DateUtils.addMonths(firstPlanStartTime, loopIndex * Integer.valueOf(plan.getRate()));
                                break;
                        }
                    }
                    endTimes = loopIndex;
                }
                for (int t = 0; t < endTimes; t++) {
                    for (int i = 0; i < targets.size(); i++) {
                        EquipmentUpkeepPlanTarget target = targets.get(i);
                        String lastUpkeepDate = DateUtil.formatDate(target.getLastUpkeepDate());//开始时机由上次保养时间
                        String lastUpkeepDateTime = lastUpkeepDate + " " + plan.getTaskPlanStartTime();//上次保养时间
                        DateTime firstPlanStartTime = DateUtil.parse(lastUpkeepDateTime);
                        Date prePlanStartTime = null;
                        switch (plan.getRateUnit()) {
                            case "日":
                                prePlanStartTime = DateUtils.addDays(firstPlanStartTime, (t+1) * Integer.valueOf(plan.getRate()));
                                break;
                            case "月":
                                prePlanStartTime = DateUtils.addMonths(firstPlanStartTime, (t+1) * Integer.valueOf(plan.getRate()));
                                break;
                        }
                        EquipmentUpkeepTask task = new EquipmentUpkeepTask();
                        task.setUpkeepType(plan.getPlanType());//计划类型
                        task.setOrderStatus(EquipmentEnums.UpkeepStatus.START.getCode());
                        task.setTargetType(plan.getTargetType());
                        task.setTargetCode(target.getTargetCode());
                        task.setTargetName(target.getTargetName());
                        task.setTargetId(target.getTargetId());
                        task.setTargetSpec(target.getTargetSpec());
                        task.setIsAutoRelease(plan.getIsAuto());
                        task.setIsPush(plan.getIsPush());//是否推送
                        task.setPlanStartTime(prePlanStartTime);//计划开始时间
                        task.setPlanEndTime(DateUtils.addHours(prePlanStartTime, plan.getPlanHourRation()));//计划结束时间=计划开始时间+计划工时
                        task.setPlanHourRation(plan.getPlanHourRation());//计划工时
                        task.setUpkeepPersonGroupCode(target.getUpkeepPersonGroupCode());//对应设备资产的保养群组
                        //task.setDispatchMode(plan.getDispatchMode());
                        task.setReleaseTargetType(plan.getReleaseTargetType());
                        //task.setReleaseTargetId(plan.getTarget());
                        //task.setReleaseTargetName(plan.getTargetName());
                        if (task.getIsAutoRelease() == 1) {//自动下达
                            task.setPlanReleaseTime(DateUtils.addDays(task.getPlanStartTime(), 0 - plan.getAdvanceTime()));//计划下达时间
                        }
                        task.setAdvanceTime(plan.getAdvanceTime());
                        task.setCreateTime(new Date());
                        if (plan.getIsHold()==0){
                            task.setPmisHold(EquipmentEnums.PmisHode.PRODUCTIONSCHEDULED.getCode());
                        }else {
                            task.setPmisHold(EquipmentEnums.PmisHode.PENDINGPRODUCTION.getCode());
                        }

                        task.setCreateBy("系统生成");

                        //标记下一个待下达任务 相关字段
                        task.setPlanId(plan.getId());
                        task.setPlanCode(plan.getCode());
                        task.setPlanName(plan.getName());
                        task.setTaskIndex(t);
                        if (t==0){
                            task.setNextFlag(CommonEnums.YesNo.YES.getCode());
                        }else{
                            task.setNextFlag(CommonEnums.YesNo.NO.getCode());
                        }
                        EquipmentEqpBasics eqpBasics = target.getEqpBasics();
                        if (eqpBasics!=null){
                            task.setEqpTypeId(eqpBasics.getEqpTypeId());
                            task.setUseDeptId(eqpBasics.getUseDeptId());
                            task.setCodeAbc(eqpBasics.getCodeAbc());
                            task.setEngineerPersonGroupCode(eqpBasics.getEngineerPersonGroupCode());
                        }
                        // 赋值taskDetail信息
                        tpmUpkeepTaskService.save(task);
                        for (int i1 = 0; i1 < planDetails.size(); i1++) {
                            EquipmentUpkeepTaskDetail taskDetail = new EquipmentUpkeepTaskDetail();
                            BeanUtils.copyProperties(planDetails.get(i1), taskDetail, "id", "createTime", "createBy", "updateTime", "updateBy", "updateTime", "sysOrgCode");
                            taskDetail.setBizNo(task.getBizNo());
                            taskDetail.setCreateBy("系统生成");
                            tpmUpkeepTaskDetailService.save(taskDetail);
                            if (taskDetail.getChooseEnable() == 1) {
                                // 如果有选项，则获取选项
                                List<EquipmentUpkeepPlanDetailParam> planDetailParams = tpmUpkeepPlanDetailParamService.selectByMainId(planDetails.get(i1).getId());
                                if (!CollectionUtils.isEmpty(planDetailParams)) {
                                    for (int i2 = 0; i2 < planDetailParams.size(); i2++) {
                                        EquipmentUpkeepTaskDetailParam taskDetailParam = new EquipmentUpkeepTaskDetailParam();
                                        taskDetailParam.setNum(planDetailParams.get(i2).getNum());
                                        taskDetailParam.setParam(planDetailParams.get(i2).getParameter());
                                        taskDetailParam.setBizNo(task.getBizNo());
                                        taskDetailParam.setDetailId(taskDetail.getId());
                                        taskDetailParam.setCreateBy("系统生成");
                                        taskDetailParam.setCreateTime(new Date());
                                        tpmUpkeepTaskDetailParamService.save(taskDetailParam);
                                    }
                                }
                            }
                        }
                    }
                }
                plan.setIsEnable(Integer.parseInt(CommonEnums.YesNo.NO.getCode()));//计划状态更改
                plan.setExecStatus(EquipmentEnums.PlanExecStatus.FINISH.getCode());//已完成
                tpmUpkeepPlanService.update(plan);
            }else if (StringUtils.equals(endLoopType, EquipmentEnums.PlanEndLoopType.LOOP.getCode())) {//按循环 仅生成下个周期的任务
                Date lastPlanEnd = plan.getLastPlanEnd();
                Date prePlanStartTime = null;
                if (lastPlanEnd==null){//未执行过任务
                    String formatPlanStartTime = planStartDate + " " + plan.getTaskPlanStartTime();
                    DateTime firstPlanStartTime = DateUtil.parse(formatPlanStartTime);
                    prePlanStartTime = firstPlanStartTime;
                }else{
                    if (DateUtil.compare(new Date(),lastPlanEnd)>=0){//大于等于上次计划结束时间时才重新生成任务
                        prePlanStartTime = lastPlanEnd;
                    }else{
                        continue;
                    }
                }
                // 获取频率，并计算出计划结束时间
                Date nextPlanStartTime = null;
                switch (plan.getRateUnit()) {
                    case "日":
                        nextPlanStartTime = DateUtils.addDays(prePlanStartTime, Integer.valueOf(plan.getRate()));
                        break;
                    case "月":
                        nextPlanStartTime = DateUtils.addMonths(prePlanStartTime, Integer.valueOf(plan.getRate()));
                        break;
                    case "年":
                        nextPlanStartTime = DateUtils.addYears(prePlanStartTime, Integer.valueOf(plan.getRate()));
                        break;
                }
                plan.setLastPlanStart(prePlanStartTime);
                plan.setLastPlanEnd(nextPlanStartTime);
                plan.setExecStatus(EquipmentEnums.PlanExecStatus.EXECING.getCode());//执行中
                Integer cycleIndex = plan.getCycleIndex();
                if (cycleIndex==null){
                    cycleIndex = 0;
                }
                plan.setCycleIndex(cycleIndex+1);//循环次数加一
                tpmUpkeepPlanService.update(plan);

                // 赋值task信息
                for (int i = 0; i < targets.size(); i++) {
                    EquipmentUpkeepPlanTarget target = targets.get(i);

                    Date targetLastPlanStart = target.getLastPlanStart();//上次保养日期
                    if (targetLastPlanStart==null){//为空
                        String lastUpkeepDate = DateUtil.formatDate(target.getLastUpkeepDate());//开始时机由上次保养时间
                        String lastUpkeepDateTime = lastUpkeepDate + " " + plan.getTaskPlanStartTime();//上次保养时间
                        targetLastPlanStart = DateUtil.parse(lastUpkeepDateTime);
                    }
                    Date curTargetPlanStart = null;
                    switch (plan.getRateUnit()) {
                        case "日":
                            curTargetPlanStart = DateUtils.addDays(targetLastPlanStart, Integer.valueOf(plan.getRate()));
                            break;
                        case "月":
                            curTargetPlanStart = DateUtils.addMonths(targetLastPlanStart, Integer.valueOf(plan.getRate()));
                            break;
                        case "年":
                            curTargetPlanStart = DateUtils.addYears(targetLastPlanStart, Integer.valueOf(plan.getRate()));
                            break;
                    }
                    target.setLastPlanStart(curTargetPlanStart);
                    tpmUpkeepPlanTargetService.update(target);//更新上次计划开始时间

                    EquipmentUpkeepTask task = new EquipmentUpkeepTask();

                    task.setPlanId(plan.getId());
                    task.setPlanCode(plan.getCode());
                    task.setPlanName(plan.getName());
                    task.setTaskIndex(cycleIndex);
                    if (cycleIndex==0){
                        task.setNextFlag(CommonEnums.YesNo.YES.getCode());
                    }else{
                        Long count = JpaUtil.linq(EquipmentUpkeepTask.class).equal("planId", plan.getId()).equal("nextFlag", CommonEnums.YesNo.YES.getCode()).count();
                        if (count>0){
                            task.setNextFlag(CommonEnums.YesNo.NO.getCode());
                        }else{
                            task.setNextFlag(CommonEnums.YesNo.YES.getCode());
                        }
                    }
                    task.setUpkeepType(plan.getPlanType());//计划类型
                    task.setOrderStatus(EquipmentEnums.UpkeepStatus.START.getCode());
                    task.setTargetType(plan.getTargetType());
                    task.setTargetCode(target.getTargetCode());
                    task.setTargetName(target.getTargetName());
                    task.setTargetId(target.getTargetId());
                    task.setTargetSpec(target.getTargetSpec());
                    task.setIsAutoRelease(plan.getIsAuto());
                    task.setPlanStartTime(curTargetPlanStart);
                    task.setIsPush(plan.getIsPush());//是否推送
                    task.setPlanEndTime(DateUtils.addHours(curTargetPlanStart, plan.getPlanHourRation()));//计划结束时间=计划开始时间+计划工时
                    task.setPlanHourRation(plan.getPlanHourRation());//计划工时
                    task.setUpkeepPersonGroupCode(target.getUpkeepPersonGroupCode());//对应设备资产的保养群组
                    //task.setDispatchMode(plan.getDispatchMode());
                    task.setReleaseTargetType(plan.getReleaseTargetType());
                    //task.setReleaseTargetId(plan.getTarget());
                    //task.setReleaseTargetName(plan.getTargetName());
                    if (task.getIsAutoRelease() == 1) {
                        task.setPlanReleaseTime(DateUtils.addDays(task.getPlanStartTime(), 0 - plan.getAdvanceTime()));
                    }
                    task.setAdvanceTime(plan.getAdvanceTime());
                    task.setCreateTime(new Date());
                    if (plan.getIsHold()==0){
                        task.setPmisHold(EquipmentEnums.PmisHode.PRODUCTIONSCHEDULED.getCode());
                    }else {
                        task.setPmisHold(EquipmentEnums.PmisHode.PENDINGPRODUCTION.getCode());
                    }
                    task.setCreateBy("系统生成");

                    EquipmentEqpBasics eqpBasics = target.getEqpBasics();
                    if (eqpBasics!=null){
                        task.setEqpTypeId(eqpBasics.getEqpTypeId());
                        task.setUseDeptId(eqpBasics.getUseDeptId());
                        task.setCodeAbc(eqpBasics.getCodeAbc());
                        task.setEngineerPersonGroupCode(eqpBasics.getEngineerPersonGroupCode());
                    }
                    // 赋值taskDetail信息
                    tpmUpkeepTaskService.save(task);
                    for (int i1 = 0; i1 < planDetails.size(); i1++) {
                        EquipmentUpkeepTaskDetail taskDetail = new EquipmentUpkeepTaskDetail();
                        BeanUtils.copyProperties(planDetails.get(i1), taskDetail, "id", "createTime", "createBy", "updateTime", "updateBy", "updateTime", "sysOrgCode");
                        taskDetail.setBizNo(task.getBizNo());
                        taskDetail.setCreateBy("系统生成");
                        tpmUpkeepTaskDetailService.save(taskDetail);
                        if (taskDetail.getChooseEnable() == 1) {
                            // 如果有选项，则获取选项
                            List<EquipmentUpkeepPlanDetailParam> planDetailParams = tpmUpkeepPlanDetailParamService.selectByMainId(planDetails.get(i1).getId());
                            if (!CollectionUtils.isEmpty(planDetailParams)) {
                                for (int i2 = 0; i2 < planDetailParams.size(); i2++) {
                                    EquipmentUpkeepTaskDetailParam taskDetailParam = new EquipmentUpkeepTaskDetailParam();
                                    taskDetailParam.setNum(planDetailParams.get(i2).getNum());
                                    taskDetailParam.setParam(planDetailParams.get(i2).getParameter());
                                    taskDetailParam.setBizNo(task.getBizNo());
                                    taskDetailParam.setDetailId(taskDetail.getId());
                                    taskDetailParam.setCreateBy("系统生成");
                                    taskDetailParam.setCreateTime(new Date());
                                    tpmUpkeepTaskDetailParamService.save(taskDetailParam);
                                }
                            }
                        }
                    }
                }
            }
            log.info("计划" + plan.getCode() + "生成保养任务调度结束："+DateUtil.formatDateTime(new Date()));
        }
    }
}
